<!DOCTYPE html>
<html lang="zh-cn">
<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
  <title>DOS DPMI下的硬件中断机制 - whowin - 发表我个人原创作品的技术博客</title>
  <meta name="renderer" content="webkit" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>

<meta http-equiv="Cache-Control" content="no-transform" />
<meta http-equiv="Cache-Control" content="no-siteapp" />

<meta name="theme-color" content="#f8f5ec" />
<meta name="msapplication-navbutton-color" content="#f8f5ec">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="#f8f5ec">


<meta name="author" content="whowin" /><meta name="description" content="本文旨在探讨DPMI(DOS Protect Mode Interface)环境下的硬件中断机制，以及在此环境下硬件中断的编写方法，本文并不探讨实模式下和保护模式下硬件中断的原理，但文中难免涉及一些这方面的知识，请读者自行阅读相关资料解决。在本文的最后将举一个硬件中断的编写实例。本文主要讨论的环境为：DOS6.22 &#43; DJGPP &#43; CWSDPMI。CWSDPMI为DJGPP自带的DPMI服务，也是一个好用的且免费的DPMI，有关这个环境的搭建，请参阅我以前的博文。本文是我2008年的作品，2023年重新整理发布，仅为存档，其中的程序并没有再次验证，特此说明。
" /><meta name="keywords" content="linux, socket, hugo, dos" />






<meta name="generator" content="Hugo 0.97.3 with theme even" />


<link rel="canonical" href="https://whowin.gitee.io/post/blog/dos/0011-hw-int-mechanism-under-dos-dpmi/" />
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
<link rel="manifest" href="/manifest.json">
<link rel="mask-icon" href="/safari-pinned-tab.svg" color="#5bbad5">



<link href="/sass/main.min.e3fea119b1980e848b03dffbeddb11dd0fba483eed0e5f11870fb8e31f145bbd.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@3.1.20/dist/jquery.fancybox.min.css" integrity="sha256-7TyXnr2YU040zfSP+rEcz29ggW4j56/ujTPwjMzyqFY=" crossorigin="anonymous">


<meta property="og:title" content="DOS DPMI下的硬件中断机制" />
<meta property="og:description" content="本文旨在探讨DPMI(DOS Protect Mode Interface)环境下的硬件中断机制，以及在此环境下硬件中断的编写方法，本文并不探讨实模式下和保护模式下硬件中断的原理，但文中难免涉及一些这方面的知识，请读者自行阅读相关资料解决。在本文的最后将举一个硬件中断的编写实例。本文主要讨论的环境为：DOS6.22 &#43; DJGPP &#43; CWSDPMI。CWSDPMI为DJGPP自带的DPMI服务，也是一个好用的且免费的DPMI，有关这个环境的搭建，请参阅我以前的博文。本文是我2008年的作品，2023年重新整理发布，仅为存档，其中的程序并没有再次验证，特此说明。" />
<meta property="og:type" content="article" />
<meta property="og:url" content="https://whowin.gitee.io/post/blog/dos/0011-hw-int-mechanism-under-dos-dpmi/" /><meta property="article:section" content="post" />
<meta property="article:published_time" content="2008-05-07T17:45:03+08:00" />
<meta property="article:modified_time" content="2008-05-07T17:45:03+08:00" />

<meta itemprop="name" content="DOS DPMI下的硬件中断机制">
<meta itemprop="description" content="本文旨在探讨DPMI(DOS Protect Mode Interface)环境下的硬件中断机制，以及在此环境下硬件中断的编写方法，本文并不探讨实模式下和保护模式下硬件中断的原理，但文中难免涉及一些这方面的知识，请读者自行阅读相关资料解决。在本文的最后将举一个硬件中断的编写实例。本文主要讨论的环境为：DOS6.22 &#43; DJGPP &#43; CWSDPMI。CWSDPMI为DJGPP自带的DPMI服务，也是一个好用的且免费的DPMI，有关这个环境的搭建，请参阅我以前的博文。本文是我2008年的作品，2023年重新整理发布，仅为存档，其中的程序并没有再次验证，特此说明。"><meta itemprop="datePublished" content="2008-05-07T17:45:03+08:00" />
<meta itemprop="dateModified" content="2008-05-07T17:45:03+08:00" />
<meta itemprop="wordCount" content="7062">
<meta itemprop="keywords" content="DOS,DPMI," /><meta name="twitter:card" content="summary"/>
<meta name="twitter:title" content="DOS DPMI下的硬件中断机制"/>
<meta name="twitter:description" content="本文旨在探讨DPMI(DOS Protect Mode Interface)环境下的硬件中断机制，以及在此环境下硬件中断的编写方法，本文并不探讨实模式下和保护模式下硬件中断的原理，但文中难免涉及一些这方面的知识，请读者自行阅读相关资料解决。在本文的最后将举一个硬件中断的编写实例。本文主要讨论的环境为：DOS6.22 &#43; DJGPP &#43; CWSDPMI。CWSDPMI为DJGPP自带的DPMI服务，也是一个好用的且免费的DPMI，有关这个环境的搭建，请参阅我以前的博文。本文是我2008年的作品，2023年重新整理发布，仅为存档，其中的程序并没有再次验证，特此说明。"/>

<!--[if lte IE 9]>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/classlist/1.1.20170427/classList.min.js"></script>
<![endif]-->

<!--[if lt IE 9]>
  <script src="https://cdn.jsdelivr.net/npm/html5shiv@3.7.3/dist/html5shiv.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/respond.js@1.4.2/dest/respond.min.js"></script>
<![endif]-->

  <script async src="/js/busuanzi.pure.mini.js"></script><script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9724909319263152"
     crossorigin="anonymous"></script>


</head>
<body>
  <div id="mobile-navbar" class="mobile-navbar">
  <div class="mobile-header-logo">
    <a href="/" class="logo">WhoWin</a>
  </div>
  <div class="mobile-navbar-icon">
    <span></span>
    <span></span>
    <span></span>
  </div>
</div>
<nav id="mobile-menu" class="mobile-menu slideout-menu">
  <ul class="mobile-menu-list">
    <a href="/">
        <li class="mobile-menu-item">首页</li>
      </a><a href="/post/">
        <li class="mobile-menu-item">文章归档</li>
      </a><a href="/article-categories/categories/">
        <li class="mobile-menu-item">文章分类</li>
      </a><a href="/tags/">
        <li class="mobile-menu-item">文章标签</li>
      </a><a href="/about/about/">
        <li class="mobile-menu-item">关于</li>
      </a>
  </ul>

  


</nav>

  <div class="container" id="mobile-panel">
    <header id="header" class="header">
        <div class="logo-wrapper">
  <a href="/" class="logo">WhoWin</a>
  
  <div style="position:absolute; left: 80px; top: 75px; color: crimson">
      ———开源和分享是技术发展的源泉和动力；本博客所有文章均为原创
  </div>
</div>





<nav class="site-navbar">
  <ul id="menu" class="menu">
    <li class="menu-item">
        <a class="menu-item-link" href="/">首页</a>
      </li><li class="menu-item">
        <a class="menu-item-link" href="/post/">文章归档</a>
      </li><li class="menu-item">
        <a class="menu-item-link" href="/article-categories/categories/">文章分类</a>
      </li><li class="menu-item">
        <a class="menu-item-link" href="/tags/">文章标签</a>
      </li><li class="menu-item">
        <a class="menu-item-link" href="/about/about/">关于</a>
      </li>
  </ul>
</nav>

    </header>

    <main id="main" class="main">
      <div class="content-wrapper">
        <div id="content" class="content">
          <article class="post">
    
    <header class="post-header">
      <h1 class="post-title">DOS DPMI下的硬件中断机制</h1>

      <div class="post-meta">
        <span class="post-time"> 2008-05-07 </span>
        <div class="post-category">
            <a href="/categories/dos/"> DOS </a>
            </div>
        
      </div>
    </header>

    <div class="post-toc" id="post-toc">
  <h2 class="post-toc-title">文章目录</h2>
  <div class="post-toc-content always-active">
    <nav id="TableOfContents">
  <ul>
    <li>
      <ul>
        <li><a href="#1dpmi下的硬件中断机理">1、DPMI下的硬件中断机理</a></li>
        <li><a href="#2dpmi下编写硬件中断的方法">2、DPMI下编写硬件中断的方法</a></li>
        <li><a href="#3dpmi下一个时钟中断的实例">3、DPMI下一个时钟中断的实例</a></li>
      </ul>
    </li>
  </ul>
</nav>
  </div>
</div>
    <div class="post-content">
      <p>本文旨在探讨DPMI(DOS Protect Mode Interface)环境下的硬件中断机制，以及在此环境下硬件中断的编写方法，本文并不探讨实模式下和保护模式下硬件中断的原理，但文中难免涉及一些这方面的知识，请读者自行阅读相关资料解决。在本文的最后将举一个硬件中断的编写实例。本文主要讨论的环境为：DOS6.22 + DJGPP + CWSDPMI。CWSDPMI为DJGPP自带的DPMI服务，也是一个好用的且免费的DPMI，有关这个环境的搭建，请参阅我以前的博文。<strong>本文是我2008年的作品，2023年重新整理发布，仅为存档，其中的程序并没有再次验证，特此说明。</strong></p>
<h2 id="1dpmi下的硬件中断机理">1、DPMI下的硬件中断机理</h2>
<blockquote>
<p>实模式下的硬件中断有很多书籍中都有介绍，保护模式下的硬件中断要复杂一些，但也有一些资料。本博客中的大部分文章将介绍在DOS环境下使用DJGPP完成保护模式下的程序，编译出来的程序需要在DPMI的支持下运行在保护模式下，通常情况下，并没有什么，当你需要调用DOS下的实模式下的功能调用时，DPMI会帮助你切换到实模式，完成后再返回保护模式，基本上不需要编程者去做任何处理事情，但在处理硬件中断方面就比较微妙了，我们究竟应该在实模式下完成硬件中断还是在保护模式下，如果原有的硬件中断工作在实模式下，而我却编了一个保护模式下的硬件中断程序，按规则，在我的中断例程完成后，我必须再执行原有的硬件中断，显然这里有些问题。</p>
</blockquote>
<blockquote>
<p>首先，不论是在实模式下还是在保护模式下，硬件中断都会产生，当程序运行在DPMI下时，尽管你的程序是32位的，运行在保护模式下，但当你调用实模式下DOS的功能调用时，DPMI会切换到实模式下，可能一个硬件中断恰恰在这个时候产生了，但不管什么时候发生了硬件中断，只要你的程序运行在DPMI下，DPMI将截获硬件中断，并将首先传送给保护模式下的硬件中断程序执行，然后再转到实模式下的中断例程；但并不是所有的DPMI都将在两种模式下执行中断例程，比如我们本文讨论的环境，CWSDPMI下，DPMI截获中断并交给保护模式下的中断例程，只有在保护模式的中断例程不存在的情况下，DPMI才会去执行实模式下的中断例程，在CWSDPMI下，DPMI只执行一种模式下的中断例程；但WINDOWS 95下的DPMI就不一样，windows宣称会执行把两种模式下的中断例程都执行一遍（抱歉，我并没有验证这一说法）；所以，一定要了解你所处的环境，在下面的叙述中，如果不特别说明，均只在CWSDPMI下，综上所述，在DPMI下，你可以只编写一个保护模式下的中断例程，而无须管实模式下的中断例程。</p>
</blockquote>
<blockquote>
<p>但是，我们毕竟是在DOS下编程，很多资源来自于实模式的DOS，所以如果你的中断程序中需要大量地调用DOS的资源时，你必须要考虑编写实模式的中断程序，否则在你的中断程序中DPMI将不断地在实模式和保护模式之间切换，这将十分麻烦。</p>
</blockquote>
<h2 id="2dpmi下编写硬件中断的方法">2、DPMI下编写硬件中断的方法</h2>
<blockquote>
<p>保护模式下的中断程序，按下面方法设置。</p>
</blockquote>
<ul>
<li>
<p>用汇编语言编写的中断程序，可以按照下面的步骤进行设置：</p>
<ul>
<li>取得原有的中断程序结构
<blockquote>
<p>调用__dpmi_get_protected_mode_interrupt_vector函数，并把返回值存在结构中，以便程序退出时可以恢复原来的中断程序</p>
</blockquote>
</li>
<li>锁定内存
<blockquote>
<p>调用__dpmi_lock_linear_region函数锁定在中断程序中可能用到的数据变量，代码，调用的函数；锁定失败有可能造成你的程序崩溃；</p>
</blockquote>
</li>
<li>设置新的中断程序
<blockquote>
<p>调用__dpmi_set_protected_mode_interrupt_vector，把新中断程序的选择子（selector）和偏移（offset）填入__dpmi_paddr中，传给函数，其中，pm_selector可以通过函数__dpmi_cs()获得</p>
</blockquote>
</li>
</ul>
</li>
<li>
<p>如果中断程序用C语言写成，可以按照下面方法设置：</p>
<ul>
<li>取得原有的中断程序结构
<blockquote>
<p>调用_go32_dpmi_get_protected_mode_interrupt_vector，将返回值存入适当的结构中，以便程序退出时恢复原有的中断程序</p>
</blockquote>
</li>
<li>对中断程序进行再包装
<blockquote>
<p>调用_go32_dpmi_allocate_iret_wrapper函数，按照要求传递参数，该函数将按照中断程序的规范建立一个小的汇编函数对你的C语言写的中断程序进行包装，该函数填充的结构_go32_dpmi_seginfo将作为下面函数调用的参数。</p>
</blockquote>
</li>
<li>设置新的中断程序
<blockquote>
<p>调用_go32_dpmi_set_protected_mode_interrupt_vector函数，把上一步骤返回的_go32_dpmi_seginfo作为参数传给该函数。</p>
</blockquote>
</li>
<li>链接原有中断
<blockquote>
<p>如果需要在执行完你的中断程序后执行原有的中断程序，不必执行前面两个步骤，直接调用_go32_dpmi_chain_protected_mode_interrupt_vector即可，就是说不用调用_go32_dpmi_allocate_iret_wrapper和_go32_dpmi_set_protected_mode_interrupt_vector这两个函数，_go32_dpmi_chain_protected_mode_interrupt_vector将完成所有的工作，在填结构_go32_dpmi_seginfo时，把中断程序的偏移放到pm_offset中，把_my_cs()的返回值放到pm_selector中即可；用这种方式设置的中断你只能通过DJGPP的退出代码进行释放，别无他法。</p>
</blockquote>
</li>
</ul>
</li>
</ul>
<blockquote>
<p>用C语言写中断程序的主要问题是你根本没有办法完全锁定你的中断程序所用到的存储器，所以，这种方法只适用于那些较小的程序，你可以确认你的程序不会被page到磁盘上去；这一点要特别引起注意，一般情况下，中断程序尽量使用汇编语言完成比较好。</p>
</blockquote>
<h2 id="3dpmi下一个时钟中断的实例">3、DPMI下一个时钟中断的实例</h2>
<ul>
<li>
<p>老实说，没有什么很好的例子可以给大家演示中断程序，本来想结合前面博文中的AC97的内容编写一个PCI的中断例子，但复杂一些，涉及的问题也比较多，好在比较幸运的是我找到了一个int 8h的例子，个人感觉写的比较简单，好懂，对这段代码做了大量的修改，原程序接管了int 8h，我修改后的程序接管了int 8h和int 70h两个中断，我觉得这样更能说明问题。</p>
</li>
<li>
<p>int 8h(IRQ 0)是时钟中断，来自可编程的时钟芯片8254，现在的机器中已经没有了这颗芯片，给集成到了别的芯片中，不过保留了原来的I/O端口及8254的控制方法，所以仍然可以使用控制8254的方法控制时钟；要说明这个例子，我们不得不先简单介绍一下8254这颗芯片。</p>
</li>
<li>
<p>8254定时器这颗芯片有三个定时通道，每个通道有一个I/O地址，timer0 - timer2对应的I/O地址为40h - 42h，这个I/O通道是8位的，通过这个8位的I/O通道可以对8254进行编程</p>
</li>
<li>
<p>8254内部有一个16位的锁存寄存器，编程时送入的计数值首先进入这个锁存寄存器，然后被复制到计数寄存器，当接到8254上的时钟信号每来一个脉冲时，这个计数寄存器中的数值将减一，当减到0时，8254将输出一个脉冲，同时再次将锁存寄存器中的内容复制到计数寄存器中，开始下一轮的计数。</p>
</li>
<li>
<p>所以，8254芯片的每个通道有两个输入信号：一个是时钟信号，一个是门控信号，用于控制该通道工作或者不工作(后面我们会提到)；一个输出信号，即计数完毕后的输出信号。</p>
</li>
<li>
<p>一般情况下，timer0用于产生每秒18.2次的系统时钟中断(int 8h)，这就是我们下面例子中要编的中断；timer1用于存储器刷新(现在应该不用了？)；timer2连接扬声器，可以产生方波使扬声器发声。这里说到的知识可能有点老，尤其是timer1的用法，不过不妨碍我们的例子。</p>
</li>
<li>
<p>8254还有一个控制寄存器，I/O地址为43h，8位通道，该寄存器的定义如下：</p>
<p><img src="https://whowin.gitee.io/images/160011/dpmi-controller_registers.jpg" alt="DPMI下的硬件中断"></p>
</li>
<li>
<p>对这个控制寄存器，还是简单说明一下：</p>
<ul>
<li>bit [6:7]
<blockquote>
<p>准备对那个定时器通道进行操作，timer0 or timer1 or timer2</p>
</blockquote>
</li>
<li>bit [4:5]
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">读/写当前计数值
</span></span><span class="line"><span class="cl">00：读当前计数值，先读低8位，后读高8位，要两次in指令
</span></span><span class="line"><span class="cl">01：只写高8位，一次out指令
</span></span><span class="line"><span class="cl">10：只写低8位，一次out指令
</span></span><span class="line"><span class="cl">11：先写低8位，后写高8位，要两次out指令
</span></span></code></pre></td></tr></table>
</div>
</div></li>
<li>bit [1:3]
<blockquote>
<p>工作模式，有6种工作模式，其中模式0（000）为计数结束后产生中断；模式3（003）为方波频率发声器，这两种模式后面要用</p>
</blockquote>
</li>
<li>bit 0
<blockquote>
<p>写入值的格式，0&ndash;二进制格式，1&ndash;BCD码格式</p>
</blockquote>
</li>
</ul>
</li>
<li>
<p>前面说到，8254的输入信号里还有一个门控信号，对于timer0和timer1，这个信号永远是选通的，但timer2的门控信号是可控的，由I/O端口61h的bit 0和bit 1控制，该I/O端口的bit0为1则关断timer2的门控信号，为0开启门控信号，bit1和可以控制timer2和扬声器的通断，我们不需要使用这个信号。</p>
</li>
<li>
<p>pc机种还有一个实时时钟中断，int 70h(IRQ 8)，由以前的MC146818这颗芯片产生，现在这颗芯片也已经集成到其他芯片中了，不过操作和控制方法还是相同，MC146818可以产生多种类型的中断，在初始状态都是关闭的，我们仅用它的周期中断，缺省为每秒1024次，我们并没有更改任何参数，仅仅是在中断中增加了一个中断计数，我们希望以此中断来检验我们接管的int 8h的正确性。</p>
</li>
<li>
<p>好了，基本知识介绍完了。下面是程序清单：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">  1
</span><span class="lnt">  2
</span><span class="lnt">  3
</span><span class="lnt">  4
</span><span class="lnt">  5
</span><span class="lnt">  6
</span><span class="lnt">  7
</span><span class="lnt">  8
</span><span class="lnt">  9
</span><span class="lnt"> 10
</span><span class="lnt"> 11
</span><span class="lnt"> 12
</span><span class="lnt"> 13
</span><span class="lnt"> 14
</span><span class="lnt"> 15
</span><span class="lnt"> 16
</span><span class="lnt"> 17
</span><span class="lnt"> 18
</span><span class="lnt"> 19
</span><span class="lnt"> 20
</span><span class="lnt"> 21
</span><span class="lnt"> 22
</span><span class="lnt"> 23
</span><span class="lnt"> 24
</span><span class="lnt"> 25
</span><span class="lnt"> 26
</span><span class="lnt"> 27
</span><span class="lnt"> 28
</span><span class="lnt"> 29
</span><span class="lnt"> 30
</span><span class="lnt"> 31
</span><span class="lnt"> 32
</span><span class="lnt"> 33
</span><span class="lnt"> 34
</span><span class="lnt"> 35
</span><span class="lnt"> 36
</span><span class="lnt"> 37
</span><span class="lnt"> 38
</span><span class="lnt"> 39
</span><span class="lnt"> 40
</span><span class="lnt"> 41
</span><span class="lnt"> 42
</span><span class="lnt"> 43
</span><span class="lnt"> 44
</span><span class="lnt"> 45
</span><span class="lnt"> 46
</span><span class="lnt"> 47
</span><span class="lnt"> 48
</span><span class="lnt"> 49
</span><span class="lnt"> 50
</span><span class="lnt"> 51
</span><span class="lnt"> 52
</span><span class="lnt"> 53
</span><span class="lnt"> 54
</span><span class="lnt"> 55
</span><span class="lnt"> 56
</span><span class="lnt"> 57
</span><span class="lnt"> 58
</span><span class="lnt"> 59
</span><span class="lnt"> 60
</span><span class="lnt"> 61
</span><span class="lnt"> 62
</span><span class="lnt"> 63
</span><span class="lnt"> 64
</span><span class="lnt"> 65
</span><span class="lnt"> 66
</span><span class="lnt"> 67
</span><span class="lnt"> 68
</span><span class="lnt"> 69
</span><span class="lnt"> 70
</span><span class="lnt"> 71
</span><span class="lnt"> 72
</span><span class="lnt"> 73
</span><span class="lnt"> 74
</span><span class="lnt"> 75
</span><span class="lnt"> 76
</span><span class="lnt"> 77
</span><span class="lnt"> 78
</span><span class="lnt"> 79
</span><span class="lnt"> 80
</span><span class="lnt"> 81
</span><span class="lnt"> 82
</span><span class="lnt"> 83
</span><span class="lnt"> 84
</span><span class="lnt"> 85
</span><span class="lnt"> 86
</span><span class="lnt"> 87
</span><span class="lnt"> 88
</span><span class="lnt"> 89
</span><span class="lnt"> 90
</span><span class="lnt"> 91
</span><span class="lnt"> 92
</span><span class="lnt"> 93
</span><span class="lnt"> 94
</span><span class="lnt"> 95
</span><span class="lnt"> 96
</span><span class="lnt"> 97
</span><span class="lnt"> 98
</span><span class="lnt"> 99
</span><span class="lnt">100
</span><span class="lnt">101
</span><span class="lnt">102
</span><span class="lnt">103
</span><span class="lnt">104
</span><span class="lnt">105
</span><span class="lnt">106
</span><span class="lnt">107
</span><span class="lnt">108
</span><span class="lnt">109
</span><span class="lnt">110
</span><span class="lnt">111
</span><span class="lnt">112
</span><span class="lnt">113
</span><span class="lnt">114
</span><span class="lnt">115
</span><span class="lnt">116
</span><span class="lnt">117
</span><span class="lnt">118
</span><span class="lnt">119
</span><span class="lnt">120
</span><span class="lnt">121
</span><span class="lnt">122
</span><span class="lnt">123
</span><span class="lnt">124
</span><span class="lnt">125
</span><span class="lnt">126
</span><span class="lnt">127
</span><span class="lnt">128
</span><span class="lnt">129
</span><span class="lnt">130
</span><span class="lnt">131
</span><span class="lnt">132
</span><span class="lnt">133
</span><span class="lnt">134
</span><span class="lnt">135
</span><span class="lnt">136
</span><span class="lnt">137
</span><span class="lnt">138
</span><span class="lnt">139
</span><span class="lnt">140
</span><span class="lnt">141
</span><span class="lnt">142
</span><span class="lnt">143
</span><span class="lnt">144
</span><span class="lnt">145
</span><span class="lnt">146
</span><span class="lnt">147
</span><span class="lnt">148
</span><span class="lnt">149
</span><span class="lnt">150
</span><span class="lnt">151
</span><span class="lnt">152
</span><span class="lnt">153
</span><span class="lnt">154
</span><span class="lnt">155
</span><span class="lnt">156
</span><span class="lnt">157
</span><span class="lnt">158
</span><span class="lnt">159
</span><span class="lnt">160
</span><span class="lnt">161
</span><span class="lnt">162
</span><span class="lnt">163
</span><span class="lnt">164
</span><span class="lnt">165
</span><span class="lnt">166
</span><span class="lnt">167
</span><span class="lnt">168
</span><span class="lnt">169
</span><span class="lnt">170
</span><span class="lnt">171
</span><span class="lnt">172
</span><span class="lnt">173
</span><span class="lnt">174
</span><span class="lnt">175
</span><span class="lnt">176
</span><span class="lnt">177
</span><span class="lnt">178
</span><span class="lnt">179
</span><span class="lnt">180
</span><span class="lnt">181
</span><span class="lnt">182
</span><span class="lnt">183
</span><span class="lnt">184
</span><span class="lnt">185
</span><span class="lnt">186
</span><span class="lnt">187
</span><span class="lnt">188
</span><span class="lnt">189
</span><span class="lnt">190
</span><span class="lnt">191
</span><span class="lnt">192
</span><span class="lnt">193
</span><span class="lnt">194
</span><span class="lnt">195
</span><span class="lnt">196
</span><span class="lnt">197
</span><span class="lnt">198
</span><span class="lnt">199
</span><span class="lnt">200
</span><span class="lnt">201
</span><span class="lnt">202
</span><span class="lnt">203
</span><span class="lnt">204
</span><span class="lnt">205
</span><span class="lnt">206
</span><span class="lnt">207
</span><span class="lnt">208
</span><span class="lnt">209
</span><span class="lnt">210
</span><span class="lnt">211
</span><span class="lnt">212
</span><span class="lnt">213
</span><span class="lnt">214
</span><span class="lnt">215
</span><span class="lnt">216
</span><span class="lnt">217
</span><span class="lnt">218
</span><span class="lnt">219
</span><span class="lnt">220
</span><span class="lnt">221
</span><span class="lnt">222
</span><span class="lnt">223
</span><span class="lnt">224
</span><span class="lnt">225
</span><span class="lnt">226
</span><span class="lnt">227
</span><span class="lnt">228
</span><span class="lnt">229
</span><span class="lnt">230
</span><span class="lnt">231
</span><span class="lnt">232
</span><span class="lnt">233
</span><span class="lnt">234
</span><span class="lnt">235
</span><span class="lnt">236
</span><span class="lnt">237
</span><span class="lnt">238
</span><span class="lnt">239
</span><span class="lnt">240
</span><span class="lnt">241
</span><span class="lnt">242
</span><span class="lnt">243
</span><span class="lnt">244
</span><span class="lnt">245
</span><span class="lnt">246
</span><span class="lnt">247
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">001 #include &lt;stdio.h&gt;
</span></span><span class="line"><span class="cl">002 #include &lt;dos.h&gt;
</span></span><span class="line"><span class="cl">003 #include &lt;string.h&gt;
</span></span><span class="line"><span class="cl">004 #include &lt;dpmi.h&gt;
</span></span><span class="line"><span class="cl">005 #include &lt;pc.h&gt;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">006 void pm_new8h(void);
</span></span><span class="line"><span class="cl">007 void lock_pm_new8h(void);
</span></span><span class="line"><span class="cl">008 void pm_new70h(void);
</span></span><span class="line"><span class="cl">009 void lock_pm_new70h(void);
</span></span><span class="line"><span class="cl">010 char *get_cmostime(void);
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">011 #define IRQ0                 0x8       // 8254 time interrupt
</span></span><span class="line"><span class="cl">012 #define IRQ8                 0x70      // Real time interrupt
</span></span><span class="line"><span class="cl">013 #define PIT0                 0x40      // 8254 timer0
</span></span><span class="line"><span class="cl">014 #define PITMODE              0x43      // 8254 control word
</span></span><span class="line"><span class="cl">    /* 8254 controll word
</span></span><span class="line"><span class="cl">        bit 7:6 timer number 00--timer0  01--timer1  10--timer2
</span></span><span class="line"><span class="cl">        bit 5:4 latch,read format;
</span></span><span class="line"><span class="cl">                00--latch current count;
</span></span><span class="line"><span class="cl">                01--write low byte(no latching);
</span></span><span class="line"><span class="cl">                10--write high byte(no latching);
</span></span><span class="line"><span class="cl">                11--write low,then high byte
</span></span><span class="line"><span class="cl">        bit 3:1 mode number;
</span></span><span class="line"><span class="cl">                000--interrupt on terminal count;
</span></span><span class="line"><span class="cl">                001--programmable one-shot;
</span></span><span class="line"><span class="cl">                010--rate generator
</span></span><span class="line"><span class="cl">                011--sequare wave generator;
</span></span><span class="line"><span class="cl">                100--software triggered strobe;
</span></span><span class="line"><span class="cl">                101--hardware triggered strobe
</span></span><span class="line"><span class="cl">        bit 0   count byte; 0--binary 1--bcd
</span></span><span class="line"><span class="cl">    */
</span></span><span class="line"><span class="cl">015 #define IMR0                 0x21       // IMR of 8259-0
</span></span><span class="line"><span class="cl">016 #define IMR1                 0xa1       // IMR of 8259-1
</span></span><span class="line"><span class="cl">017 #define RTC_ADDR             0x70
</span></span><span class="line"><span class="cl">018 #define RTC_DATA             0x71
</span></span><span class="line"><span class="cl">019 #define PITCONST             1193180L   // Frequence of 8254
</span></span><span class="line"><span class="cl">020 #define PIT0DEF              18.2067597 // ticks per sec of previous int
</span></span><span class="line"><span class="cl">021 #define RT_MS_PER_TICK       0.9765625
</span></span><span class="line"><span class="cl">022 #define NEW8H                1          // flag. new int 8h valiable.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">023 static float tick_per_ms    = 0.0182068;  // ticks per ms
</span></span><span class="line"><span class="cl">024 static float ms_per_tick    = 54.9246551; // interval between two ticks
</span></span><span class="line"><span class="cl">025 static float freq8h         = 18.2067597; // frequency of system timer
</span></span><span class="line"><span class="cl">026 static unsigned char flag8h = 0;
</span></span><span class="line"><span class="cl">027 static _go32_dpmi_seginfo old_handler_8h, new_handler_8h;
</span></span><span class="line"><span class="cl">028 static _go32_dpmi_seginfo old_handler_70h, new_handler_70h;
</span></span><span class="line"><span class="cl">029 static _go32_dpmi_registers r;
</span></span><span class="line"><span class="cl">030 unsigned long int ticks_8h  = 0;
</span></span><span class="line"><span class="cl">031 unsigned long int ticks_70h = 0;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    /***********************************************
</span></span><span class="line"><span class="cl">    * New int 8h initialization
</span></span><span class="line"><span class="cl">    * It chains int routine of protected mode and
</span></span><span class="line"><span class="cl">    * real mode
</span></span><span class="line"><span class="cl">    ***********************************************/
</span></span><span class="line"><span class="cl">032 void pctimer_init(unsigned int Hz) {
</span></span><span class="line"><span class="cl">033     unsigned int pit0_set, pit0_value;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">034     if (flag8h != NEW8H) {      // Current int 8h is old.
</span></span><span class="line"><span class="cl">035         disable();                // Disable interrupts
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">036         lock_pm_new8h();         // Lock int routine in protected mode
</span></span><span class="line"><span class="cl">037         lock_pm_new70h();        // Lock int routine in protected mode
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">            // Lock some var that will be used in int routine
</span></span><span class="line"><span class="cl">038         _go32_dpmi_lock_data(&amp;ticks_8h, sizeof(ticks_8h));
</span></span><span class="line"><span class="cl">039         _go32_dpmi_lock_data(&amp;ticks_70h, sizeof(ticks_70h));
</span></span><span class="line"><span class="cl">040         _go32_dpmi_lock_data(&amp;r, sizeof(r));
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">            // Get the previous int routine in protected mode
</span></span><span class="line"><span class="cl">            // and chain a new routine
</span></span><span class="line"><span class="cl">041         _go32_dpmi_get_protected_mode_interrupt_vector(IRQ0, &amp;old_handler_8h);
</span></span><span class="line"><span class="cl">042         new_handler_8h.pm_offset = (int)pm_new8h;
</span></span><span class="line"><span class="cl">043         new_handler_8h.pm_selector = _go32_my_cs();
</span></span><span class="line"><span class="cl">044         _go32_dpmi_chain_protected_mode_interrupt_vector(IRQ0, &amp;new_handler_8h);
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">045         _go32_dpmi_get_protected_mode_interrupt_vector(IRQ8, &amp;old_handler_70h);
</span></span><span class="line"><span class="cl">046         new_handler_70h.pm_offset   = (int)pm_new70h;
</span></span><span class="line"><span class="cl">047         new_handler_70h.pm_selector = _go32_my_cs();
</span></span><span class="line"><span class="cl">048         _go32_dpmi_allocate_iret_wrapper(&amp;new_handler_70h);
</span></span><span class="line"><span class="cl">049         _go32_dpmi_set_protected_mode_interrupt_vector(IRQ8, &amp;new_handler_70h);
</span></span><span class="line"><span class="cl">            // initial RTC
</span></span><span class="line"><span class="cl">050         outportb(RTC_ADDR, 0x0b);
</span></span><span class="line"><span class="cl">051         outportb(RTC_DATA, 0x42);
</span></span><span class="line"><span class="cl">            // initial 8259-2
</span></span><span class="line"><span class="cl">052         outportb(IMR1, 0x0c);
</span></span><span class="line"><span class="cl">            // initial Timer0 of 8254
</span></span><span class="line"><span class="cl">053         outportb(PITMODE, 0x36);      // 8254 command register
</span></span><span class="line"><span class="cl">                                          // 00110110b.timer0,write low and high
</span></span><span class="line"><span class="cl">                                          // sequare wave generator,binary
</span></span><span class="line"><span class="cl">054         pit0_value = PITCONST / Hz;
</span></span><span class="line"><span class="cl">055         pit0_set = (pit0_value &amp; 0x00ff);
</span></span><span class="line"><span class="cl">056         outportb (PIT0, pit0_set);
</span></span><span class="line"><span class="cl">057         pit0_set = (pit0_value &gt;&gt; 8);
</span></span><span class="line"><span class="cl">058         outportb (PIT0, pit0_set);
</span></span><span class="line"><span class="cl">059         // initial vars for int
</span></span><span class="line"><span class="cl">060         ticks_8h      = 0;
</span></span><span class="line"><span class="cl">061         flag8h        = NEW8H;               // new int 8h
</span></span><span class="line"><span class="cl">062         freq8h        = Hz;                  // frequence of new int
</span></span><span class="line"><span class="cl">063         tick_per_ms   = freq8h / 1000;       // ticks per ms
</span></span><span class="line"><span class="cl">064         ms_per_tick   = 1000 / freq8h;       // ms of per tick
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">065         enable();                           // enable interrupts
</span></span><span class="line"><span class="cl">066     }
</span></span><span class="line"><span class="cl">067 }
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">068 void pctimer_exit(void) {
</span></span><span class="line"><span class="cl">069     unsigned int pit0_set, pit0_value;
</span></span><span class="line"><span class="cl">070     unsigned long tick;
</span></span><span class="line"><span class="cl">071     char *cmostime;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">072     if (flag8h == NEW8H) {
</span></span><span class="line"><span class="cl">073         disable();
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">074         outportb(PITMODE, 0x36);
</span></span><span class="line"><span class="cl">075         outportb(PIT0, 0x00);
</span></span><span class="line"><span class="cl">076         outportb(PIT0, 0x00);
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">077         outportb(RTC_ADDR, 0x0b);
</span></span><span class="line"><span class="cl">078         outportb(RTC_DATA, 0x02);
</span></span><span class="line"><span class="cl">079         outportb(IMR1, 0x0d);
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">080         _go32_dpmi_set_protected_mode_interrupt_vector(IRQ0, &amp;old_handler_8h);
</span></span><span class="line"><span class="cl">081         _go32_dpmi_free_iret_wrapper(&amp;new_handler_70h);
</span></span><span class="line"><span class="cl">082         _go32_dpmi_set_protected_mode_interrupt_vector(IRQ8, &amp;old_handler_70h);
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">083         enable();
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">084         cmostime = get_cmostime();
</span></span><span class="line"><span class="cl">085         tick = PIT0DEF *
</span></span><span class="line"><span class="cl">                (
</span></span><span class="line"><span class="cl">                    (((float) *cmostime) * 3600) +
</span></span><span class="line"><span class="cl">                    (((float) *(cmostime + 1)) * 60) +
</span></span><span class="line"><span class="cl">                    (((float) *(cmostime + 2)))
</span></span><span class="line"><span class="cl">                );
</span></span><span class="line"><span class="cl">086         biostime(1, tick);
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">087         flag8h = 0;
</span></span><span class="line"><span class="cl">088         freq8h = PIT0DEF;
</span></span><span class="line"><span class="cl">089         tick_per_ms = freq8h / 1000;
</span></span><span class="line"><span class="cl">090         ms_per_tick = 1000 / freq8h;
</span></span><span class="line"><span class="cl">091     }
</span></span><span class="line"><span class="cl">092 }
</span></span><span class="line"><span class="cl">    /****************************************
</span></span><span class="line"><span class="cl">    * New int 8h routine in protected mode
</span></span><span class="line"><span class="cl">    ****************************************/
</span></span><span class="line"><span class="cl">093 void pm_new8h(void) {
</span></span><span class="line"><span class="cl">094     ticks_8h++;
</span></span><span class="line"><span class="cl">095 }
</span></span><span class="line"><span class="cl">    /************************************************
</span></span><span class="line"><span class="cl">    * Lock the memory of new int 8h routine region
</span></span><span class="line"><span class="cl">    * in protected mode
</span></span><span class="line"><span class="cl">    ************************************************/
</span></span><span class="line"><span class="cl">096 void lock_pm_new8h(void) {
</span></span><span class="line"><span class="cl">097     _go32_dpmi_lock_code(pm_new8h, (unsigned long)(lock_pm_new8h - pm_new8h));
</span></span><span class="line"><span class="cl">098 }
</span></span><span class="line"><span class="cl">    /****************************************
</span></span><span class="line"><span class="cl">    * New int 70h routine in protected mode
</span></span><span class="line"><span class="cl">    ****************************************/
</span></span><span class="line"><span class="cl">099 void pm_new70h(void) {
</span></span><span class="line"><span class="cl">100     disable();
</span></span><span class="line"><span class="cl">101     ticks_70h++;
</span></span><span class="line"><span class="cl">102     outportb(RTC_ADDR, 0x0c);
</span></span><span class="line"><span class="cl">103     inportb(RTC_DATA);
</span></span><span class="line"><span class="cl">104     outportb(0xa0, 0x20);
</span></span><span class="line"><span class="cl">105     outportb(0x20, 0x20);
</span></span><span class="line"><span class="cl">106     enable();
</span></span><span class="line"><span class="cl">107 }
</span></span><span class="line"><span class="cl">    /************************************************
</span></span><span class="line"><span class="cl">    * Lock the memory of new int 70h routine region
</span></span><span class="line"><span class="cl">    * in protected mode
</span></span><span class="line"><span class="cl">    ************************************************/
</span></span><span class="line"><span class="cl">108 void lock_pm_new70h(void) {
</span></span><span class="line"><span class="cl">109     _go32_dpmi_lock_code(pm_new70h, (unsigned long)(lock_pm_new70h - pm_new70h));
</span></span><span class="line"><span class="cl">110 }
</span></span><span class="line"><span class="cl">    /*****************************************
</span></span><span class="line"><span class="cl">    * Sleep delayms ms
</span></span><span class="line"><span class="cl">    *****************************************/
</span></span><span class="line"><span class="cl">111 void pctimer_sleep(unsigned int delayms) {
</span></span><span class="line"><span class="cl">112     unsigned long int delaytick;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">113     delaytick = delayms * tick_per_ms + ticks_8h;
</span></span><span class="line"><span class="cl">114     do {
</span></span><span class="line"><span class="cl">115     } while (ticks_8h &lt;= delaytick);
</span></span><span class="line"><span class="cl">116 }
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">117 char *get_cmostime(void) {
</span></span><span class="line"><span class="cl">118     char *buff;
</span></span><span class="line"><span class="cl">119     static char buffer[6];
</span></span><span class="line"><span class="cl">120     char ch;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">121     buff = buffer;
</span></span><span class="line"><span class="cl">122     memset(&amp;r, 0, sizeof (r));
</span></span><span class="line"><span class="cl">123     r.h.ah = 0x02;
</span></span><span class="line"><span class="cl">124     _go32_dpmi_simulate_int(0x1a, &amp;r);
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">125     ch = r.h.ch;
</span></span><span class="line"><span class="cl">126     buffer[0] = (char)((int)(ch &amp; 0x0f) + (int)((ch &gt;&gt; 4) &amp; 0x0f) * 10);
</span></span><span class="line"><span class="cl">127     ch = r.h.cl;
</span></span><span class="line"><span class="cl">128     buffer[1] = (char)((int)(ch &amp; 0x0f) + (int)((ch &gt;&gt; 4) &amp; 0x0f) * 10);
</span></span><span class="line"><span class="cl">129     ch = r.h.dh;
</span></span><span class="line"><span class="cl">130     buffer[2] = (char)((int)(ch &amp; 0x0f) + (int)((ch &gt;&gt; 4) &amp; 0x0f) * 10);
</span></span><span class="line"><span class="cl">131     buffer[3] = r.h.dl;
</span></span><span class="line"><span class="cl">132     buffer[4] = (char)(r.x.flags &amp; 0x0001);
</span></span><span class="line"><span class="cl">133     buffer[5] = 0x00;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">134     return(buff);
</span></span><span class="line"><span class="cl">135 }
</span></span><span class="line"><span class="cl">    // Main program
</span></span><span class="line"><span class="cl">136 int main(void) {
</span></span><span class="line"><span class="cl">137     int i;
</span></span><span class="line"><span class="cl">138     unsigned long int start, finish;
</span></span><span class="line"><span class="cl">139     int elapsedtime[20];
</span></span><span class="line"><span class="cl">140     float average_error, sum = 0;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">141     printf(&#34;Press any key to begin the test. &#34;);
</span></span><span class="line"><span class="cl">142     printf(&#34;(It lasts for 20 seconds.)\n\n&#34;);
</span></span><span class="line"><span class="cl">143     getch();
</span></span><span class="line"><span class="cl">144     printf(&#34;Test in progress.  Please wait...\n&#34;);
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">145     pctimer_init(1000);         // 1000Hz, 1000 ticks per sec
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">146     for (i = 0; i &lt; 10; i++) {
</span></span><span class="line"><span class="cl">147         start = ticks_70h;
</span></span><span class="line"><span class="cl">148         pctimer_sleep(1000);
</span></span><span class="line"><span class="cl">149         finish = ticks_70h;
</span></span><span class="line"><span class="cl">150         elapsedtime[i] = (int)(finish - start);
</span></span><span class="line"><span class="cl">151     }
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">152     pctimer_exit();
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">153     printf(&#34;Test finished.\n&#34;);
</span></span><span class="line"><span class="cl">154     printf(&#34;Press any key to display the result...\n&#34;);
</span></span><span class="line"><span class="cl">155     getch();
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">156     for (i = 0; i &lt; 10; i++) {
</span></span><span class="line"><span class="cl">157         sum += (float)((elapsedtime[i] - 1024) * RT_MS_PER_TICK);
</span></span><span class="line"><span class="cl">158         printf(&#34;iteration:%2d  expected:1024  observed:%d  difference:%d\n&#34;,
</span></span><span class="line"><span class="cl">                    i + 1, elapsedtime[i], elapsedtime[i] - 1024);
</span></span><span class="line"><span class="cl">159     }
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">160     average_error = (float)sum / 10;
</span></span><span class="line"><span class="cl">161     printf(&#34;\ntotal error:%.2f ms  average error:%.2f ms\n&#34;,
</span></span><span class="line"><span class="cl">                sum, average_error);
</span></span><span class="line"><span class="cl">162     return 0;
</span></span><span class="line"><span class="cl">163 }
</span></span></code></pre></td></tr></table>
</div>
</div></li>
<li>
<p>为了说明方便，源程序中加了行号，所有的注释语句没有行号。</p>
</li>
<li>
<p>先大概说一下这个程序完成的事情</p>
<blockquote>
<p>PC机系统的时钟中断是18.2次/秒，本程序重新编写了系统时钟中断int 8h，试图做到1ms中断一次，链接到原中断上，这样int 8h(IRQ 0)的中断频率将从18.2Hz变成1000Hz，这势必影响到PC机的时钟，因为很多资源是依赖这个时钟中断的，比如时间；同时我们接管了实时时钟中断int 70h(IRQ 8)，并启动了它的周期中断，中断频率应该是1024Hz，在这个中断中我们仅仅作了一个中断计数；主程序中在启动中断后做了10次的循环，每次循环前记录int 70h的中断次数计数值，然后等待int 8h中断1000次(应该刚好1秒钟)，然后再记录int 70h的中断次数计数值，理论上说，int 8h中断1000次，int 70h应该刚好中断1024次，如果数值吻合，说明int 8h完全按照我们的预期在运行。</p>
</blockquote>
</li>
<li>
<p>常量、变量说明：</p>
<ul>
<li>ticks_8h：int 8h的中断次数计数</li>
<li>ticks_70h：int 70h的中断次数计数</li>
<li>PIT0：8254 timer0的端口地址，我们要修改timer0的设置</li>
<li>PITMODE：8254的控制寄存器</li>
<li>IMR1：第二颗8259中断控制器的中断屏蔽寄存器地址，因为IRQ 8连在第2颗8259上</li>
<li>RTC_ADDR：实时时钟芯片（MC146818）地址寄存器地址</li>
<li>RTC_DATA：实时时钟芯片（MC146818）数据寄存器地址</li>
</ul>
</li>
<li>
<p>主程序从136行开始，145行调用pctimer_init初始化两个硬件中断，传递的参数1000表明把int 8h的中断频率设成1000Hz；146行&ndash;151行是测试部分的主循环，前面有过介绍，pctimer_sleep(1000)可以等待int 8h中断1000次，最后把int 70h在此期间的中断次数记录在数组elapsedtime中，共后面显示结果用；循环完毕后，调用pctimer_exit恢复以前的中断，然后显示测试记录。</p>
</li>
<li>
<p>比较复杂的部分是函数pctimer_init，从32行&ndash;67行。</p>
<ul>
<li>35行关中断</li>
<li>36、37行锁定了两个中断程序的代码</li>
<li>38&ndash;40行锁定了中断程序中要用到的数据</li>
<li>41&ndash;44行设置了int 8h（IRQ 0）</li>
<li>45&ndash;49行设置了int 70h（IRQ 8），注意这两个中断的设置方法是有所不同的，我们把int 8h与原来的中断链接到了一起，而int 70h没有链接原来的中断，读者可以通过这段代码体会其中的不同</li>
<li>50、51行设置了实时时钟芯片的状态寄存器B，目的是开启周期中断，读者可以参考与实时时钟芯片相关的资料</li>
<li>52行重新设置了第二颗8259中断控制器，目的是清除对IRQ 8的屏蔽，这里要注意的是，在我做测试的机器上，我读取了第一颗8259的中断屏蔽寄存器，知道其用于级联第二颗8259的IRQ 2并没有被屏蔽，所以我并没有设置第一颗8259的中断屏蔽寄存器，如果你的机器与我的不同，请注意设置第一颗8259的中断屏蔽寄存器，打开IRQ 2，另外，我知道我的机器第二颗8259的中断屏蔽寄存器的缺省设置值是0dh，刚好IRQ 8被屏蔽了，所以我直接送了一个0ch到第二颗8259的中断屏蔽寄存器，以打开IRQ 8，在你的机器上可能也有些不同，请按实际情况设置，只要打开IRQ 8即可，不要改变其他的屏蔽位，以免麻烦，由于此处并非本文的重点，所以在代码上没有作更多处理</li>
<li>54&ndash;58行初始化8254的timer0，请参考前面关于8254芯片的介绍部分，另外在14和15行之间的注释也有一个对8254的简单介绍</li>
<li>60&ndash;64行设置了一些变量，明白变量的含义就好了，源程序中有注释</li>
<li>65行打开中断，此时两个新的中断开始运行了</li>
</ul>
</li>
<li>
<p>93&ndash;95行是int 8h的中断程序，没有什么好说的，只是不断递增ticks_8h这个变量，注意int 8h这个中断程序是要链接到原有中断上的，所以最后不需要向8259发出中断结束的指令</p>
</li>
<li>
<p>99&ndash;107行是int 70h的中断程序，需要做一些说明，首先102、103行读取了实时时钟芯片的状态寄存器C，这是必须要做的，否则芯片认为你没有响应前一个中断，不会发出下一个中断；另外，这个中断和int 8h不同，没有链接到原有中断，所以你必须向8259发出中断完成的指令，又因为IRQ 8连接在第二颗8259上，而第二颗8259通过第一颗8259级联，所以必须向两颗8259均发出中断完成的指令，这就是104、105行的作用</p>
</li>
<li>
<p>117&ndash;135行这段程序对本文不重要，这是因为我们改变了系统时钟中断（int 8h）的中断频率，这势必导致本机时间混乱，所以在退出时，读取以下实时时钟芯片中的实时时间，然后重新设置一下时间</p>
</li>
<li>
<p>68&ndash;92行这段程序基本上是pctimer_init这个函数的逆动作，也不需要过多说明</p>
</li>
<li>
<p>至此，程序解释完了，希望能给你一些帮助。</p>
</li>
</ul>
<hr>
<p><strong>欢迎访问我的博客：https://whowin.cn</strong></p>
<p><strong>email: <a href="mailto:hengch@163.com">hengch@163.com</a></strong></p>
<p><img src="https://whowin.gitee.io/images/qrcode/sponsor-qrcode.png" alt="donation"></p>
    </div>

    <div class="post-copyright">
  <p class="copyright-item">
    <span class="item-title">文章作者</span>
    <span class="item-content">whowin</span>
  </p>
  <p class="copyright-item">
    <span class="item-title">上次更新</span>
    <span class="item-content">
        2008-05-07
        
    </span>
  </p>
  
  
</div>
<footer class="post-footer">
      <div class="post-tags">
          <a href="/tags/dos/">DOS</a>
          <a href="/tags/dpmi/">DPMI</a>
          </div>
      <nav class="post-nav">
        <a class="prev" href="/post/blog/dos/0012-install-allegro-under-dos-djgpp/">
            <i class="iconfont icon-left"></i>
            <span class="prev-text nav-default">在DJGPP&#43;DOS下安装ALLEGRO</span>
            <span class="prev-text nav-mobile">上一篇</span>
          </a>
        <a class="next" href="/post/blog/dos/0010-ac97-programing-in-dos/">
            <span class="next-text nav-default">在DOS下针对AC&#39;97编程</span>
            <span class="next-text nav-mobile">下一篇</span>
            <i class="iconfont icon-right"></i>
          </a>
      </nav>
    </footer>
  </article>
        </div>
        

  <span id="/post/blog/dos/0011-hw-int-mechanism-under-dos-dpmi/" class="leancloud_visitors" data-flag-title="DOS DPMI下的硬件中断机制">
		<span class="post-meta-item-text">文章阅读量 </span>
		<span class="leancloud-visitors-count">0</span>
		<p></p>
	  </span>
  <div id="vcomments"></div>
  <script src="//cdn1.lncld.net/static/js/3.0.4/av-min.js"></script>
  <script src='//unpkg.com/valine/dist/Valine.min.js'></script>
  <script type="text/javascript">
    new Valine({
        el: '#vcomments' ,
        appId: 'OFCGzCfJRUglzOdzrqMGkbTR-gzGzoHsz',
        appKey: 'v7P29kPAEbsmaavaYPNhGhnF',
        notify:  false ,
        verify:  false ,
        avatar:'mm',
        placeholder: '说点什么吧...',
        visitor:  true 
    });
  </script>

  

      </div>
    </main>

    <footer id="footer" class="footer">
      <div class="social-links">
      <a href="mailto:hengch@163.com" class="iconfont icon-email" title="email"></a>
  <a href="https://whowin.gitee.io/index.xml" type="application/rss+xml" class="iconfont icon-rss" title="rss"></a>
</div>
<div class="copyright">
  <span class="power-by">
    由 <a class="hexo-link" href="https://gohugo.io">Hugo</a> 强力驱动
  </span>
  <span class="division">|</span>
  <span class="theme-info">
    主题 - 
    <a class="theme-link" href="https://github.com/olOwOlo/hugo-theme-even">Even</a>
  </span>

  <div class="busuanzi-footer">
    <span id="busuanzi_container_site_pv"> 本站总访问量 <span id="busuanzi_value_site_pv"><img src="/img/spinner.svg" alt="spinner.svg"/></span> 次 </span>
      <span class="division">|</span>
    <span id="busuanzi_container_site_uv"> 本站总访客数 <span id="busuanzi_value_site_uv"><img src="/img/spinner.svg" alt="spinner.svg"/></span> 人 </span>
  </div>

  <span class="copyright-year">
    &copy; 
    2022 - 
    2024<span class="heart"><i class="iconfont icon-heart"></i></span><span>whowin</span>
  </span>
</div>

    </footer>

    <div class="back-to-top" id="back-to-top">
      <i class="iconfont icon-up"></i>
    </div>
  </div>
  
  <script src="https://cdn.jsdelivr.net/npm/jquery@3.2.1/dist/jquery.min.js" integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4=" crossorigin="anonymous"></script>
  <script src="https://cdn.jsdelivr.net/npm/slideout@1.0.1/dist/slideout.min.js" integrity="sha256-t+zJ/g8/KXIJMjSVQdnibt4dlaDxc9zXr/9oNPeWqdg=" crossorigin="anonymous"></script>
  <script src="https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@3.1.20/dist/jquery.fancybox.min.js" integrity="sha256-XVLffZaxoWfGUEbdzuLi7pwaUJv1cecsQJQqGLe7axY=" crossorigin="anonymous"></script>



<script type="text/javascript" src="/js/main.min.64437849d125a2d603b3e71d6de5225d641a32d17168a58106e0b61852079683.js"></script>
  <script type="text/javascript">
    window.MathJax = {
      tex: {
        inlineMath: [['$','$'], ['\\(','\\)']],
        }
    };
  </script>
  <script async src="https://cdn.jsdelivr.net/npm/mathjax@3.0.5/es5/tex-mml-chtml.js" integrity="sha256-HGLuEfFcsUJGhvB8cQ8nr0gai9EucOOaIxFw7qxmd+w=" crossorigin="anonymous"></script>








</body>
</html>
